use chrono::{offset, DateTime, Duration, Utc};
use cron::Schedule;
use model_graph_types::modeling::scheduler::SchedulerTask;
use std::str::FromStr;

use crate::scheduler::job_execute;

pub struct SimpleJob {
    pub schedule: Schedule,
    pub last_tick: Option<DateTime<Utc>>,
    pub limit_missed_runs: usize,
    pub task: SchedulerTask,
    pub job_id: String,
}

impl SimpleJob {
    ///
    pub fn new(task: SchedulerTask) -> anyhow::Result<SimpleJob> {
        let expression = task.cron.clone();
        let schedule = Schedule::from_str(expression.as_str()).unwrap();
        Ok(SimpleJob {
            schedule,
            last_tick: None,
            limit_missed_runs: 1,
            job_id: task.identifier.clone(),
            task,
        })
    }

    pub fn tick(&mut self) {
        let now = Utc::now();
        if self.last_tick.is_none() {
            self.last_tick = Some(now);
            return;
        }
        if self.limit_missed_runs > 0 {
            for event in self
                .schedule
                .after(&self.last_tick.unwrap())
                .take(self.limit_missed_runs)
            {
                if event > now {
                    break;
                }
                //执行
                job_execute(&self.task);
            }
        } else {
            for event in self.schedule.after(&self.last_tick.unwrap()) {
                if event > now {
                    break;
                }
                //执行
                job_execute(&self.task);
            }
        }

        self.last_tick = Some(now);
    }

    pub fn limit_missed_runs(&mut self, limit: usize) {
        self.limit_missed_runs = limit;
    }

    pub fn last_tick(&mut self, last_tick: Option<DateTime<Utc>>) {
        self.last_tick = last_tick;
    }
}
